﻿
// MFCDrawingBoardView.cpp: CMFCDrawingBoardView 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFCDrawingBoard.h"
#endif

#include "MFCDrawingBoardDoc.h"
#include "MFCDrawingBoardView.h"

#include "MainFrm.h"
//#include <utility>
#include "graphicShape/GraphicShape.h"
#include "graphicShape/graphFactor.h"

#define ID_HOTKEY_CLEAR 2001

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMFCDrawingBoardView

IMPLEMENT_DYNCREATE(CMFCDrawingBoardView, CView)

BEGIN_MESSAGE_MAP(CMFCDrawingBoardView, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCDrawingBoardView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_LBUTTONUP()
	ON_WM_HOTKEY()
	ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

// CMFCDrawingBoardView 构造/析构

void CMFCDrawingBoardView::reset()
{
	m_emShape = SE_NONE;
	m_bRubber = false;
	m_bDragging = false;
	m_bDrawing = false;
	m_nSelectedGraphID = 0;
}

CMFCDrawingBoardView::CMFCDrawingBoardView() noexcept
{
	// TODO: 在此处添加构造代码

}

CMFCDrawingBoardView::~CMFCDrawingBoardView()
{
}

BOOL CMFCDrawingBoardView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CMFCDrawingBoardView 绘图

void CMFCDrawingBoardView::OnDraw(CDC* pDC)
{
	CMFCDrawingBoardDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码

	// 如果绘图结束,才重绘
	if ( !m_bDrawing )
	{
		CustomDraw();
	}
}


// CMFCDrawingBoardView 打印


void CMFCDrawingBoardView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CMFCDrawingBoardView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CMFCDrawingBoardView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CMFCDrawingBoardView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}

void CMFCDrawingBoardView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CMFCDrawingBoardView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CMFCDrawingBoardView 诊断

#ifdef _DEBUG
void CMFCDrawingBoardView::AssertValid() const
{
	CView::AssertValid();
}

void CMFCDrawingBoardView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CMFCDrawingBoardDoc* CMFCDrawingBoardView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCDrawingBoardDoc)));
	return (CMFCDrawingBoardDoc*)m_pDocument;
}
#endif //_DEBUG


// CMFCDrawingBoardView 消息处理程序


void CMFCDrawingBoardView::OnInitialUpdate()
{
	CView::OnInitialUpdate();

	// TODO: 在此添加专用代码和/或调用基类
	CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd); 
	m_pWndClassView = &pFrame->m_wndClassView;
	std::function<void()> callback = std::bind(&CMFCDrawingBoardView::Clear, this);
	m_pWndClassView->SET.SetCallback(callback);
	RegisterHotKey(GetSafeHwnd(), ID_HOTKEY_CLEAR, MOD_ALT , 'C');
}


void CMFCDrawingBoardView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	m_startPoint = point;
	m_prePoint = point;

	// 设置画笔为红色
	if (1 == m_pWndClassView->SET.m_radioRed.GetCheck())
	{
		m_emShape = SE_LINE;
		m_bDrawing = true;
	}

	// 设置画笔为黑色
	if (1 == m_pWndClassView->SET.m_radioBlack.GetCheck())
	{
		m_emShape = SE_LINE;
		m_bDrawing = true;
	}

	// 蓝色矩形
	if (1 == m_pWndClassView->SET.m_radioRect.GetCheck())
	{
		m_emShape = SE_RECT;
		m_bDrawing = true;
	}

	// 绿色圆形
	if (1 == m_pWndClassView->SET.m_radioCircle.GetCheck())
	{
		m_emShape = SE_CIRCLE;
		m_bDrawing = true;
	}

	// 黄色椭圆
	if (1 == m_pWndClassView->SET.m_radioEllipse.GetCheck())
	{
		m_emShape = SE_ELLIPSE;
		m_bDrawing = true;
	}

	// 橡皮擦
	if (1 == m_pWndClassView->SET.m_radioRubber.GetCheck())
	{
		m_bRubber = true;
	}

	// 拖动绘制好的图形
	if (1 == m_pWndClassView->SET.m_radioDrag.GetCheck())
	{
		m_bDragging = CanDragGraph();
	}

	Invalidate(false);

	CView::OnLButtonDown(nFlags, point);
}

float CMFCDrawingBoardView::ChangePos(float num, int mode)
{
	float n = num;
	CRect rc;
	GetClientRect(rc);
	float width = rc.right - rc.left;
	float height = rc.top - rc.bottom;
	if (mode == 1)
		n = (width - 2 * n) / height;
	else
		n = n / height * 2 + 1;

	return n;
}

void CMFCDrawingBoardView::CustomDraw(const std::shared_ptr<CGraphicShapeBase>& pDrawGraphBase)
{
	// 根据 RAII 特性, 对 opengl 的绘图清屏, 并且重绘
	AutoRefreshOpenglBuffer o;

	CustomDrawHistory();

	pDrawGraphBase->Draw();
}

void CMFCDrawingBoardView::CustomDraw()
{
	// 根据 RAII 特性, 对 opengl 的绘图清屏, 并且重绘
	AutoRefreshOpenglBuffer o;

	CustomDrawHistory();
}

void CMFCDrawingBoardView::CustomDrawHistory()
{
	for (const auto& v : m_listPoint)
	{
		v->Draw();
	}
}

void CMFCDrawingBoardView::DelGraph(const CPoint& point)
{
	/*char szBuf[1024] = { 0 };
	sprintf_s(szBuf, "共有 %d 个图形\n", m_listPoint.size());
	OutputDebugString(szBuf);*/
	for (auto iter = m_listPoint.begin(); iter != m_listPoint.end();)
	{
		bool b = (*iter)->AtGraphBorder(point);
		if (b)
		{
			int nUniqueID = (*iter)->GetUniqueID();
			// 每次只删除一个
			m_listPoint.erase(iter++);
			m_mapPoint.erase(nUniqueID);
			return;
		}
		else
		{
			++iter;
		}
	}
}

// 在鼠标左键按下的移动过程中 和 鼠标左键弹起时, 调用此函数
// 把 curPoint 作为参照坐标点, 拖动图形
void CMFCDrawingBoardView::DragGraph(const CPoint& curPoint)
{
	auto iter = m_mapPoint.find(m_nSelectedGraphID);
	if ( iter != m_mapPoint.end())
	{
		auto pPairPoint = iter->second;
		pPairPoint->Move(m_prePoint, curPoint);
	}
}

bool CMFCDrawingBoardView::CanDragGraph()
{
	for ( const auto& v : m_listPoint)
	{
		bool b = v->AtGraphBorder(m_startPoint);
		if (b)
		{
			// 每次只拖动一个图形
			m_nSelectedGraphID = v->GetUniqueID();
			return true;
		}
	}

	return false;
}

int CMFCDrawingBoardView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	m_pDC = std::make_unique<CClientDC>(this);
	m_pInitOpengl = std::make_unique<InitOpenGL>(m_pDC->GetSafeHdc());
	m_pGraphFactor = std::make_unique<CGraphFactor>();
	
	return 0;
}


void CMFCDrawingBoardView::OnDestroy()
{
	CView::OnDestroy();

	// TODO: 在此处添加消息处理程序代码
}


void CMFCDrawingBoardView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// TODO: 在此处添加消息处理程序代码

	m_pInitOpengl->SetGlOrtho(cx, cy);
}


void CMFCDrawingBoardView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	Invalidate(false);

	// 画图形
	if (m_bDrawing && (m_startPoint != point) )
	{
		std::function<float(float, int)> fn = std::bind(&CMFCDrawingBoardView::ChangePos, 
			this, std::placeholders::_1, std::placeholders::_2);

		auto pDrawGraph = m_pGraphFactor->CreateGraph(m_startPoint, point, m_emShape, fn);
		if (pDrawGraph != nullptr)
		{
			// 黑线
			if ( ( m_emShape ==SE_LINE ) && (1 == m_pWndClassView->SET.m_radioBlack.GetCheck()) )
			{
				pDrawGraph->SetRGB(0.0f, 0.0f, 0.0f);
			}

			pDrawGraph->SetUniqueID(m_nInc++);

			// 绘制
			CustomDraw(pDrawGraph);
			m_listPoint.push_back(pDrawGraph);
			m_mapPoint[pDrawGraph->GetUniqueID()] = pDrawGraph;
		}
	}

	// 橡皮擦
	if (m_bRubber)
	{
		if (m_startPoint == point)
		{
			DelGraph(m_startPoint);
		}
	}

	reset();
	CView::OnLButtonUp(nFlags, point);
}


void CMFCDrawingBoardView::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if ( ID_HOTKEY_CLEAR == nHotKeyId)
	{
		Clear();
	}

	CView::OnHotKey(nHotKeyId, nKey1, nKey2);
}


void CMFCDrawingBoardView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (m_bDrawing)
	{
		std::function<float(float, int)> fn = std::bind(&CMFCDrawingBoardView::ChangePos, 
			this, std::placeholders::_1, std::placeholders::_2);

		// 临时使用的对象,用于绘图
		auto pDrawGraph = m_pGraphFactor->CreateGraph(m_startPoint, point, m_emShape, fn);
		if (pDrawGraph != nullptr)
		{
			// 黑线
			if ( ( m_emShape ==SE_LINE ) && (1 == m_pWndClassView->SET.m_radioBlack.GetCheck()) )
			{
				pDrawGraph->SetRGB(0.0f, 0.0f, 0.0f);
			}

			pDrawGraph->SetUniqueID(m_nInc++);

			CustomDraw(pDrawGraph);
			Invalidate(false);
		}
	}

	if ( m_bDragging )
	{
		DragGraph(point);
		CustomDraw();
	}

	m_prePoint = point;

	CView::OnMouseMove(nFlags, point);
}


void CMFCDrawingBoardView::Clear()
{
	// TODO: 在此处添加实现代码.
	Invalidate(false);
	m_listPoint.clear();
	m_mapPoint.clear();
	// 根据 RAII 特性, 对 opengl 的绘图清屏, 并且重绘
	AutoRefreshOpenglBuffer o;
}
